package guo.reflection;

import guo.myinterface.MyInterfaceOne;
import guo.myinterface.UserThisConstructor;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.Map;

public class Container {

    private Map<Class<?>, Method> classmaps;
    private Object serviceConfig;


    /**
     * 	存储config对象实例，和config方法的返回类型和方法本身 一一对应 映射成map
     * 	init方法得到config类方法
     * @throws ClassNotFoundException
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public void init() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        classmaps = new HashMap<Class<?>,Method>();
        Class<?> clazz = Class.forName("guo.reflection.Serviceconfig");
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method:methods){
            method.setAccessible(true);
            if (method.getDeclaredAnnotation(MyInterfaceOne.class) != null){
                classmaps.put(method.getReturnType(),method);
            }
        }
        this.serviceConfig = clazz.newInstance();
        System.out.println("serviceConfig" +serviceConfig);
    }

    /**
     * 	getServiceByClassTpe(Class<?> clazz) 方法 通过返回值类型得到服务对象
     * 		传入要加载的类型class，
     * 		若在map中找到对应key就调用method方法得到实例化对象。
     * @param clazz
     * @return
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public Object getServiceByClassType(Class<?> clazz) throws InvocationTargetException, IllegalAccessException {

        if (classmaps.containsKey(clazz)){
            Method method = classmaps.get(clazz);
            Object obj = method.invoke(serviceConfig);
            return obj;
        }
        return null;
    }

    /**
     *
     createInstance(Class<?> clazz)方法 通过class对象创建实例，
     并且将服务自动注入到对象里面。
     * @param clazz
     * @return
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     * @throws NoSuchMethodException
     * @throws InstantiationException
     */

    public Object createInstance(Class<?> clazz) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException {
        Constructor<?>[] constructors = clazz.getDeclaredConstructors();
        Object[] objs = null;
        Parameter[] parameters = null;
        for (Constructor constructor:constructors){
            if (constructor.getDeclaredAnnotation(UserThisConstructor.class) != null){
                parameters = constructor.getParameters();
                objs = new Object[parameters.length];
                for (int i = 0; i < parameters.length; i++){
                    Object o = this.getServiceByClassType(parameters[i].getType());
                    objs[i] = o;
                }
                return constructor.newInstance(objs);
            }
        }
        return clazz.getConstructor().newInstance();
    }
}
